package com.taoym.voucher.xcx.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.taoym.voucher.common.constant.CommonConstant;
import com.taoym.voucher.common.enums.UserFormalEnum;
import com.taoym.voucher.common.response.AccessTokenResp;
import com.taoym.voucher.common.response.ResponseStatusCode;
import com.taoym.voucher.common.response.XcxLoginCommon;
import com.taoym.voucher.common.utils.ExceptionCore;
import com.taoym.voucher.common.utils.HttpClientUtils;
import com.taoym.voucher.common.utils.JwtTokenUtils;
import com.taoym.voucher.common.utils.SecureUtils;
import com.taoym.voucher.xcx.domain.SysUser;
import com.taoym.voucher.xcx.domain.XcxUserInfo;
import com.taoym.voucher.xcx.entity.dto.XcxLoginDTO;
import com.taoym.voucher.xcx.entity.vo.XcxLoginVO;
import com.taoym.voucher.xcx.mapper.XcxUserInfoMapper;
import com.taoym.voucher.xcx.service.RedisService;
import com.taoym.voucher.xcx.service.SysUserService;
import com.taoym.voucher.xcx.service.XcxService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: taoym
 * @date: 2021/5/2 23:18
 * @desc: 小程序服务接口实现类
 */
@Service
@Slf4j
public class XcxServiceImpl implements XcxService {

    @Resource
    private XcxUserInfoMapper xcxUserInfoMapper;
    @Value("${nginx.path}")
    private String nginxPath;
    @Value("${file.upload}")
    private String fileUpload;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private RedisService redisService;

    @Override
    public XcxLoginVO xcxLogin(XcxLoginDTO data) {
        XcxLoginVO xcxLoginVO = new XcxLoginVO();
        XcxLoginCommon xcxLoginCommon = openId(data.getCode());

        // 查询用户是否存在
        XcxUserInfo xcxUserInfo = xcxUserInfoMapper.selectOne(new QueryWrapper<XcxUserInfo>()
                .select("uid", "formal")
                .eq("open_id", SecureUtils.encode(xcxLoginCommon.getOpenId())));

        // 如果数据库没有该用户
        if (ObjectUtils.isEmpty(xcxUserInfo)) {
            // 用户不存在 注册
            // 使用redis获取全局唯一UID
            Long uid = redisService.generateIncrementOneUID("UID");
            xcxUserInfo = new XcxUserInfo();
            xcxUserInfo.setCreateTime(LocalDateTime.now());
            xcxUserInfo.setOpenId(SecureUtils.encode(xcxLoginCommon.getOpenId()));
            xcxUserInfo.setFormal(UserFormalEnum.NO.getCode());
            xcxUserInfo.setUid(String.valueOf(uid));
            xcxUserInfo.setChiefUid(ObjectUtils.isEmpty(data.getChiefUid()) ? "000000" : data.getChiefUid());
            xcxUserInfoMapper.insert(xcxUserInfo);
        }
        Map<String, Object> claims = new HashMap<>();
        claims.put("uid", xcxUserInfo.getUid());
        String token = JwtTokenUtils.createJwtToken(claims, false);

        xcxLoginVO.setToken(token);
        xcxLoginVO.setFormal(xcxUserInfo.getFormal());
        SysUser sysUser = sysUserService.getSysUser();
        // 可分配佣金
        String distRate = sysUser.getDistRate();
        // 团队佣金
        String teamRate = sysUser.getTeamRate();
        xcxLoginVO.setRate(new BigDecimal(distRate).multiply(new BigDecimal(teamRate)).setScale(2, BigDecimal.ROUND_DOWN).toString());
        xcxLoginVO.setUid(xcxUserInfo.getUid());
        return xcxLoginVO;
    }

    @Override
    public AccessTokenResp getAccessToken() {
        Object redisObj = redisTemplate.opsForValue().get(CommonConstant.ACCESS_TOKEN_KEY);
        if (ObjectUtils.isEmpty(redisObj)) {
            throw new ExceptionCore(ResponseStatusCode.ACCESS_TOKEN_IS_NOT_EXIST);
        }
        return (AccessTokenResp) redisObj;
    }

    @Override
    public String createQRCode(String uid) {
        Map<String, Object> param = new HashMap<>();
        param.put("scene", uid);

        CloseableHttpClient httpClient = HttpClients.createDefault();

        CloseableHttpResponse response = null;
        InputStream content = null;
        FileOutputStream fos = null;
        try {
            HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + getAccessToken().getAccess_token());
            httpPost.addHeader("content-type", "application/json;charset=utf-8");
            httpPost.addHeader("accept", "application/json");
            httpPost.setEntity(new StringEntity(JSON.toJSONString(param), "UTF-8"));
            response = httpClient.execute(httpPost);
            content = response.getEntity().getContent();
            String fileName = UUID.fastUUID().toString();

            File folder = new File(fileUpload);
            if (!folder.exists()) {
                folder.mkdirs();
            }
            File file = new File(fileUpload + fileName + ".png");
            fos = new FileOutputStream(file);
            byte[] b = new byte[1024];
            int nRead = 0;
            while ((nRead = content.read(b)) != -1) {
                fos.write(b, 0, nRead);
            }
            return nginxPath + fileName + ".png";
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.flush();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (content != null) {
                try {
                    content.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    @Override
    public XcxLoginCommon openId(String code) {
        SysUser sysUser = sysUserService.getSysUser();
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + sysUser.getAppId() + "&secret=" + sysUser.getAppSecret() + "&js_code=" + code + "&grant_type=authorization_code";
        String response = HttpClientUtils.doGet(url);
        XcxLoginCommon xcxLoginCommon = JSON.parseObject(response, XcxLoginCommon.class);
        if (!ObjectUtils.isEmpty(xcxLoginCommon.getErrcode())) {
            log.warn("xcx openId info is {}", xcxLoginCommon);
            throw new ExceptionCore(ResponseStatusCode.OPEN_ID_GET_FAIL);
        }
        return xcxLoginCommon;
    }
}
